#include <stdio.h>
#include <stdlib.h>
#include <cctype>
#include <string>
#include <iostream>
#include <vector>

// Type Declarations

enum PrintBehavior {
    CloseAtSameLine,
    CloseAtOtherLine
};

/* Constant Declarations */
char Look;                    // Lookahead Character
char Class;
char Sign;
char Typ;
const int buf_len = 64;
int DLevel = 0; // Debug log level

/* Print Token. Usage: PrintEnter(Token, CloseAtOtherLine/CloseAtSameLine).
   If CloseAtOtherLine, when going out of the Token name scope, you must call PrintLeave().
 */
void PrintEnter(const char* s, PrintBehavior behavior = CloseAtOtherLine) {
    for (int i = 0; i < DLevel; ++i) {
        printf("\t");
    }
    printf("<%s", s);
    if (behavior == CloseAtSameLine) {
        printf(">\n");
    }
    else {
        printf("\n");
        ++DLevel;
    }
}

void PrintLeave() {
    for (int i = 1; i < DLevel; ++i) {
        printf("\t", DLevel);
    }
    printf(">\n");
    --DLevel;
}

/* Read New Character From Input Stream */
void GetChar() {
  Look = getchar();
}

/* Report an Error */
template<typename T>
void WriteLn(const T& t) {
    std::cout << t << std::endl;
}

void Error(const std::string& s) {
  std::cout << std::endl;
  std::cout << "Error: " << s << "." << std::endl;
}

/* Report Error and Halt */
void Abort(const std::string& s) {
    Error(s);
    exit(0);
}

/* Report What Was Expected */
void Expected(const std::string& s) {
    Abort(s + " Expected");
}

/* Recognize White Space */
int IsWhite(char c) {
    if (c==' ' ||
        c=='\t') {
        return 1;
    }
    else {
        return 0;
    }
    // return isspace(c);
}

/* Skip Over Leading White Space */
void SkipWhite() {
  while (IsWhite(Look)) {
	GetChar();
  }
}

// Skip Over a Comma
void SkipComma() {
    SkipWhite();
    if (Look == ',') {
        GetChar();
        SkipWhite();
    }
}


// Skip a CRLF
void Fin() {
    while ((Look == '\n') || (Look == '\r')) {
        GetChar();
    }
    SkipWhite();
}

/* Match a Specific Input Character */
void Match(char x) {
  if (Look == x) {
	GetChar();
  }
  else {
	char buf[buf_len] = {0};
	sprintf(buf, "'''' %c ''''", x);
	Expected(buf);
  }
}

/* Recognize an Alpha Character  */
int IsAlpha(char c) {
  return isalpha(c);
}

/* Recognize a Decimal Digit */
int IsDigit(char c) {
  return isdigit(c);
}

/* Recognize an Addop */
int IsAddop(char c) {
  if ((c == '+') ||
	  (c == '-')) {
	return 1;
  }
  else {
	return 0;
  }
}

/* Get an Identifier */
char GetName() {
  if (!IsAlpha(Look)) {
	Expected("Name");
  }

  char result = Look;
  GetChar();
  return result;
}

/* Get a Number */
char GetNum() {
  if (!IsDigit(Look)) {
	Expected("Integer");
  }

  char result = Look;
  GetChar();
  return result;
}

/* Output a String with Tab */
void EmitLn(const std::string& s) {
  std::cout << "\t " << s << std::endl;
}

/* Pose a Label To Output */
void PostLabel(const std::string& L) {
    std::cout << L << std::endl;
}


// Write the Prolog
void Prolog() {
    EmitLn("WARMST EQU $A01E");
}

// Write the Epilog
void Epilog(char c) {
    EmitLn("DC WARMST");
    std::string s(1, c);
    EmitLn("END " + s);
}

// Process Label Statement
void Labels() {
    Match('l');
}

// Process Const Statement
void Constants() {
    Match('c');
}

// Process Type Statement
void Types() {
    Match('t');
}

// Process Var Statement
void Variables() {
    Match('v');
}

// Process Procedure Definition
void DoProcedure() {
    Match('p');
}

// Process Function Definition
void DoFunction() {
    Match('f');
}

// Parse and Translate the Declaration Part
void Declarations() {
    while (true) {
        switch(Look) {
        case 'l':
            Labels();
            break;
        case 'c':
            Constants();
            break;
        case 't':
            Types();
            break;
        case 'v':
            Variables();
            break;
        case 'p':
            DoProcedure();
            break;
        case 'f':
            DoFunction();
            break;
        default:
            return;
        }
    }
}

// Get a Storage Class Specifier
void GetClass() {
    if (Look == 'a' ||
        Look == 'x' ||
        Look == 's') {
        Class = Look;
        GetChar();
    }
    else {
        Class = 'a';
    }
}

// Get a Type Specifier
void GetType() {
    Typ      = ' ';
    if (Look == 'u') {
        Sign = 'u';
        Typ  = 'i';
        GetChar();
    }
    else {
        Sign = 's';
    }

    if (Look == 'i' ||
        Look == 'l' ||
        Look == 'c') {
        Typ = Look;
        GetChar();
    }
}

// Process a Function Definition
void DoFunc(char n) {
    Match('(');
    Match(')');
    Match('{');
    Match('}');
    if (Typ == ' ') {
        Typ = 'i';
    }

    std::cout << Class << Sign << Typ << " function " << n << std::endl;
}

// Process a Data Declaration
void DoData(char n) {
    if (Typ == ' ') {
        Expected("Type Declaration");
    }
    std::cout << Class << Sign << Typ << " data " << n << std::endl;
    while (Look == ',') {
        Match(',');
        std::cout << Class << Sign << Typ << " data " << GetName() << std::endl;
    }
    Match(';');
}
    
// Process a Top-Level Declaration
void TopDecl() {
    char Name = GetName();
    if (Look == '(') {
        DoFunc(Name);
    }
    else {
        DoData(Name);
    }
}

// Parse and Translate the Statement Part
void Statements() {
    Match('b');
    while (Look != 'e') {
        GetChar();
    }
    Match('e');
}

// Parse and Translate a Pascal Block
void DoBlock(char Name) {
    Declarations();
    PostLabel(std::string(1, Name));
    Statements();
}

// Parse and Translate A Program
void Program() {
    // 0xff = ^Z = <C-q 32 RET>
    while (Look != (char)0xff) {
        GetClass();
        GetType();
        TopDecl();
    }
}

/* Initialize */
void Init() {
    GetChar();
}

/* Main Program */
int main(int argc, char** argv) {
  Init();

  Program();
  return 0;
}
